import 'dart:convert';

import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:get/utils.dart';
import 'package:oi_ai_tool/util/http/intercept/data.dart';
import 'package:oi_ai_tool/util/http/intercept/error.dart';
import 'package:oi_ai_tool/util/http/oi_response.dart';

class OiHttpRequest {
  static final OiHttpRequest _instance = OiHttpRequest._internal();

  factory OiHttpRequest() => _instance;

  static late final Dio dio;
  final CancelToken _cancelToken = CancelToken();

  OiHttpRequest._internal() {
    // BaseOptions、Options、RequestOptions 都可以配置参数，优先级别依次递增，且可以根据优先级别覆盖参数
    var options = BaseOptions();
    dio = Dio(options);

    // // 添加 request 拦截器
    dio.interceptors.addAll([
      HttpIntercept(),
      ErrorInterceptor(),
    ]);
  }

  ///初始化公共属性
  ///
  /// [baseUrl] 地址前缀
  /// [connectTimeout] 连接超时赶时间
  /// [receiveTimeout] 接收超时赶时间
  /// [interceptors] 基础拦截器
  void init({
    String? baseUrl,
    int connectTimeout = 15000,
    int receiveTimeout = 15000,
    Map<String, String>? headers,
    List<Interceptor>? interceptors,
  }) {
    dio.options = dio.options.copyWith(
        baseUrl: baseUrl,
        connectTimeout: Duration(milliseconds: connectTimeout),
        receiveTimeout: Duration(milliseconds: receiveTimeout),
        headers: headers ?? const {},
        responseType: ResponseType.json);
    if (interceptors != null && interceptors.isNotEmpty) {
      dio.interceptors.addAll(interceptors);
    }
  }

  // 关闭 dio
  void cancelRequests({required CancelToken token}) {
    _cancelToken.cancel("cancelled");
  }

  Future get(
    String path, {
    Map<String, dynamic>? params,
    Options? options,
    CancelToken? cancelToken,
    bool refresh = false,
    String? cacheKey,
    bool cacheDisk = false,
    bool showError = true,
    bool logResponse = false,
  }) async {
    var requestOptions = options ?? Options();
    requestOptions = requestOptions.copyWith(
      extra: {"showError": showError},
    );
    Response response;
    response = await dio.get(
      path,
      queryParameters: params,
      options: requestOptions,
      cancelToken: cancelToken ?? _cancelToken,
    );
    _logResponse(response: response, logResponse: logResponse);
    return response.data;
  }

  Future post<T>(
    String path, {
    Map<String, dynamic>? params,
    data,
    Options? options,
    CancelToken? cancelToken,
    bool showError = true,
    bool logResponse = false,
  }) async {
    var requestOptions = options ?? Options();
    requestOptions = requestOptions.copyWith(
      extra: {"showError": showError},
    );
    var response = await dio.post<T>(
      path,
      data: data,
      queryParameters: params,
      options: requestOptions,
      cancelToken: cancelToken ?? _cancelToken,
    );
    _logResponse(response: response, logResponse: logResponse);
    // String type = response.headers.value("content-type")!;

    return response.data;
  }

  Future put(
    String path, {
    data,
    Map<String, dynamic>? params,
    Options? options,
    CancelToken? cancelToken,
    bool showError = true,
  }) async {
    var requestOptions = options ?? Options();
    requestOptions = requestOptions.copyWith(
      extra: {"showError": showError},
    );
    var response = await dio.put(
      path,
      data: data,
      queryParameters: params,
      options: requestOptions,
      cancelToken: cancelToken ?? _cancelToken,
    );
    return response.data;
  }

  Future patch(
    String path, {
    data,
    Map<String, dynamic>? params,
    Options? options,
    CancelToken? cancelToken,
    bool showError = true,
  }) async {
    var requestOptions = options ?? Options();
    requestOptions = requestOptions.copyWith(
      extra: {"showError": showError},
    );
    var response = await dio.patch(
      path,
      data: data,
      queryParameters: params,
      options: requestOptions,
      cancelToken: cancelToken ?? _cancelToken,
    );
    return response.data;
  }

  Future delete(
    String path, {
    data,
    Map<String, dynamic>? params,
    Options? options,
    CancelToken? cancelToken,
    bool showError = true,
  }) async {
    var requestOptions = options ?? Options();
    requestOptions = requestOptions.copyWith(
      extra: {"showError": showError},
    );
    var response = await dio.delete(
      path,
      data: data,
      queryParameters: params,
      options: requestOptions,
      cancelToken: cancelToken ?? _cancelToken,
    );
    return response.data;
  }

  ///上传单个文件
  Future uploadFile(
    String path, {
    Map<String, dynamic>? params,
    FormData? data,
    Options? options,
    CancelToken? cancelToken,
    ProgressCallback? onSendProgress,
  }) async {
    var requestOptions = options ?? Options();
    var response = await dio.post(path,
        data: data,
        queryParameters: params,
        options: requestOptions,
        cancelToken: cancelToken ?? _cancelToken,
        onSendProgress: onSendProgress);
    return response.data;
  }

  _logResponse({required Response response, bool logResponse = false}) {
    if (kDebugMode && logResponse) {
      final data = response.data;
      if (data is CommonResult) {
        GetUtils.printFunction('[http][response]:', '', jsonEncode(data.data));
      }
    }
  }
}
